<?php

namespace app\common\service;

use think\facade\Cache;
use think\facade\Log;
use utils\tools\VerificationCode;
use utils\tools\MailService;
use utils\sms\AliSmsService;
use utils\sms\JisuSmsService;
use utils\sms\JuheSmsService;

class VerificationCodeService
{
    protected $config;

    public function __construct(array $config = [])
    {
        // 默认配置
        $defaultConfig = [
            'length' => 6,
            'expire' => 300, // 5分钟
            'sms_enable' => false,
            'sms_default' => 'ali_sms',
            'mail_subject' => '验证码',
            'mail_username' => '用户',
            'mail_template' => '<!DOCTYPE html><html><head><style>.code {font-size: 28px; padding: 15px; background: #f0f8ff;display: inline-block; letter-spacing: 8px;}</style></head><body><p>尊敬的 {username} ：</p><p>您申请的验证码是：<span class="code"> {code} </span></p> <p><small>有效期{expire_minutes}分钟 | 请勿转发</small></p><hr><p>如有疑问，请联系 support@example.com</p></body></html>',
        ];
        // 从配置文件加载配置，并与默认配置合并
        // 假设配置存储在 config/verification.php 和 config/rds.php 中
        $this->config = array_merge($defaultConfig, config('verification', []), config('rds', []));
        $this->config = array_merge($this->config, $config); // 允许运行时传入配置覆盖
    }



    /**
     * 生成指定位数的随机数字验证码
     *
     * @param int $length 验证码长度
     * @return string
     */
    public function generateCode(int $length = 0): string
    {
        if ($length === 0) {
            $length = $this->config['length'];
        }
        return VerificationCode::genCode($length);
    }

    /**
     * 存储验证码到缓存
     *
     * @param string $key 缓存键名
     * @param string $code 验证码
     * @param int $expire 有效期（秒）
     * @return bool
     */
    public function cacheCode(string $key, string $code, int $expire = 0): bool
    {
        if ($expire === 0) {
            $expire = $this->config['expire'];
        }
        return VerificationCode::cacheCode($key, $code, $expire);
    }

    /**
     * 验证用户提交的验证码
     *
     * @param string $key 缓存键名
     * @param string $inputCode 用户输入的验证码
     * @return bool
     */
    public function verifyCode(string $key, string $inputCode): bool
    {
        return VerificationCode::verifyCode($key, $inputCode);
    }

    /**
     * 发送验证码
     *
     * @param string $type 发送类型，可选值：'sms' (短信) 或 'email' (邮件)
     * @param string $recipient 接收者，手机号或邮箱地址
     * @param string $code 要发送的验证码
     * @param array $options 额外选项，如邮件主题、用户名等
     * @return bool
     * @throws \Exception
     */
    public function send(string $type, string $recipient, string $code, array $options = []): bool
    {
        try {
            if ($type === 'sms') {
                return $this->sendSms($recipient, $code, $options['smsService'] ?? null);
            } elseif ($type === 'email') {
                $subject = $options['subject'] ?? $this->config['mail_subject'];
                $username = $options['username'] ?? $this->config['mail_username'];
                return $this->sendEmail($recipient, $code, $subject, $username);
            } else {
                throw new \Exception('不支持的发送类型: ' . $type);
            }
        } catch (\Exception $e) {
            Log::error('验证码发送失败: ' . $e->getMessage());
            throw $e; // 重新抛出异常，以便上层捕获
        }
    }

    /**
     * 发送短信验证码
     *
     * @param string $mobile 手机号
     * @param string $code 验证码
     * @param string|null $smsService 指定短信服务商，如果为 null，则使用配置中的默认服务商
     * @return bool
     * @throws \Exception
     */
    public function sendSms(string $mobile, string $code, ?string $smsService = null): bool
    {
        if (!$this->config['sms_enable']) {
            throw new \Exception('短信服务未启用');
        }

        $serviceToUse = $smsService ?? $this->config['sms_default'];

        $data = ['mobile' => $mobile, 'code' => $code];

        switch ($serviceToUse) {
            case 'ali_sms':
                return AliSmsService::sendSms($data);
            case 'jisu_sms':
                return JisuSmsService::sendSms($data);
            case 'juhe_sms':
                return JuheSmsService::sendSms($data);
            default:
                throw new \Exception('不支持的短信服务商: ' . $serviceToUse);
        }
    }

    /**
     * 发送邮件验证码
     *
     * @param string $email 邮箱地址
     * @param string $code 验证码
     * @param string $subject 邮件主题
     * @param string $username 收件人名称
     * @return bool
     * @throws \Exception
     */
    public function sendEmail(string $email, string $code, string $subject, string $username): bool
    {
        $mailService = new MailService();
        $expireMinutes = $this->config['expire'] / 60;
        $body = str_replace(
            ['{username}', '{code}', '{expire_minutes}'],
            [$username, $code, $expireMinutes],
            $this->config['mail_template']
        );

        return $mailService->send($email, $username, $subject, $body);
    }
}